const path = require('path');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const ModulePlugin = require('./config/webpack.plugin');
const proxy = require('./config/server.proxy');

const { name, version, config } = require('./package.json');

const appName = name;

module.exports = (props, env) => {
  const mode = env.mode;
  const isEnvProduction = mode === 'production';

  const appPath = path.resolve(process.cwd());
  const commonPath = path.resolve(process.cwd(), '../shell-ui');
  const buildPath = path.resolve(process.cwd(), config.build[mode], config.output);

  console.log('appName', appName);
  console.log('appPath', appPath);

  const resolve = {
    extensions: ['.jsx', '.js', '.json', '.css', '.less'],
    alias: {
      '@shell-ui': path.join(commonPath, 'src'),
      '@variables': path.join(commonPath, 'assets/styles/variables.less'),
      '@assets': path.join(appPath, 'assets'),
      '@app': path.join(appPath, 'src/app'),
      '@views': path.join(appPath, 'src/views'),
      '@constant': path.join(appPath, 'src/constant'),
      '@components': path.join(appPath, 'src/components'),
      '@utils': path.join(appPath, 'src/utils')
    }
  };

  const optimization = {
    minimize: true,
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        uglifyOptions: {
          output: {
            comments: false
          },
          compress: {
            warnings: false,
            collapse_vars: true,
            reduce_vars: true,
            drop_console: true
          }
        }
      })
    ],
    namedChunks: true,
    splitChunks: {
      cacheGroups: {
        vendors: {
          name: 'vendors',
          test: /[\\/]node_modules[\\/]/,
          minChunks: 1,
          priority: -10,
          reuseExistingChunk: true
        },
        default: false
      }
    }
  };

  const getModule = () => {
    const styleLoader = isEnvProduction ? {
      loader: MiniCssExtractPlugin.loader,
      options: {
        publicPath: '../'
      }
    } : 'style-loader';
    // const styleLoader = 'style-loader';
    return {
      rules: [
        {
          test: /\.(js|jsx)$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              // presets: [['@babel/preset-env', { modules: 'cjs' }], '@babel/preset-react'],
              presets: [['@babel/preset-env'], '@babel/preset-react'],
              plugins: [
                ['@babel/plugin-proposal-decorators', { legacy: true }],
                ['@babel/plugin-proposal-class-properties', { loose: true }],
                ['@babel/plugin-transform-runtime', { regenerator: true }]
              ],
              cacheDirectory: true
            }
          }
        },
        {
          test: /\.less$/,
          include: /\.module\.less$/,
          exclude: /node_modules/,
          use: [
            styleLoader,
            {
              loader: 'css-loader',
              options: {
                importLoaders: 1,
                modules: {
                  localIdentName: '[local]_[hash:base64:5]'
                },
                localsConvention: 'camelCase'
              }
            },
            'less-loader'
          ],
          sideEffects: true
        },
        {
          test: /\.less$/,
          exclude: /\.module\.less$/,
          use: [
            styleLoader,
            'css-loader',
            'less-loader'
          ]
        },
        {
          test: /\.css$/i,
          use: [
            styleLoader,
            'css-loader'
          ]
        },
        {
          test: /\.(png|jpg|jpeg|gif)$/,
          use: [
            {
              loader: 'url-loader',
              options: {
                limit: 1024 * 32,
                name: 'images/[name].[hash:8].[ext]'
              }
            }
          ]
        },
        {
          test: /\.(woff(2)?|otf|eot|svg|ttf)$/,
          use: [
            {
              loader: 'url-loader',
              options: {
                limit: 1024 * 16,
                name: 'fonts/[name].[ext]'
              }
            }
          ]
        }
      ]
    };
  };

  const pluginsCommon = [
    new webpack.ProvidePlugin({
      _: 'lodash'
    }),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(mode),
        APP_NAME: JSON.stringify(appName),
        SUB_MODULE_OUTPUT: JSON.stringify(config.output)
      }
    }),
    new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /en/),
    new webpack.DllReferencePlugin({
      context: path.resolve(process.cwd()),
      manifest: path.join(appPath, config.build[mode], 'static', 'dll.manifest.json')
    })
  ];

  const commonConfig = {
    mode,
    devtool: isEnvProduction ? false : 'cheap-module-eval-source-map',
    entry: {
      [appName]: `./${config.entry[mode]}`
    },
    output: {
      path: buildPath,
      publicPath: isEnvProduction ? path.join('/', config.publicPath, config.output, '/') : '/',
      filename: isEnvProduction ? '[name].[contenthash:6].js' : '[name].js',
      chunkFilename: 'chunks/[name].[chunkhash:6].js',
      library: isEnvProduction ? undefined : 'common'
    },
    module: getModule(isEnvProduction),
    resolve,
    externals: {
      '@common/components': 'window.common.components',
      '@common/utils': 'window.common.utils',
      '@common/hooks': 'window.common.hooks',
      '@common/shell': 'window.common.shell'
    }
  };

  const developmentConfig = {
    stats: 'minimal',
    watchOptions: {
      aggregateTimeout: 200,
      poll: 100,
      ignored: /node_modules/
    },
    devServer: {
      host: '0.0.0.0',
      contentBase: './dist',
      port: config.port,
      compress: true,
      hot: true,
      inline: true,
      proxy
    },
    plugins: [
      ...pluginsCommon,
      new webpack.HotModuleReplacementPlugin(),
      new HtmlWebPackPlugin({
        template: './config/index.html',
        filename: 'index.html'
      })
    ]
  };

  const productionConfig = {
    optimization,
    plugins: [
      ...pluginsCommon,
      new CleanWebpackPlugin(buildPath, { allowExternal: true }),
      new MiniCssExtractPlugin({
        filename: 'css/[name].[contenthash:6].css',
        chunkFilename: 'css/[name].[chunkhash:6].chunk.css'
      }),
      new ModulePlugin({ name: appName, version })
    ]
  };

  switch (mode) {
    case 'development':
      return webpackMerge(commonConfig, developmentConfig);
    case 'production':
    default:
      return webpackMerge(commonConfig, productionConfig);
  }
};
